/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package station3d.graphics;

import station3d.*;
import station3d.math.*;

import java.awt.event.KeyEvent;

/**
 *
 * @author Martin
 */
public class CameraController {

    private final InputManager inputManager;

    private InputManager.InputState middleMouseButton;
    private InputManager.InputState left, right, up, down;
    private InputManager.InputState mouseWheelUp, mouseWheelDown;

    private static final double CAMERA_MIN_Y = 10;
    private static final double ZOOM_STEP_Y = 10;
    private static final double ZOOM_SPEED_Y = 0.00008;

    private final Vector3D cameraPosition;
    private final Vector3D cameraOrientation;

    private Vector3D cameraSpot = new Vector3D();

    private boolean zooming = false;
    private enum ZoomDirection { UP, DOWN };
    private ZoomDirection zoomDirection;
    private double zoomYTo;


    public CameraController(InputManager inputManager) {
        this.inputManager = inputManager;

        middleMouseButton = new InputManager.InputState();
        left = new InputManager.InputState();
        right = new InputManager.InputState();
        up = new InputManager.InputState();
        down = new InputManager.InputState();
        mouseWheelUp = new InputManager.InputState(InputManager.InputState.InputStateBehavior.CATCH_ONLY_ONCE);
        mouseWheelDown = new InputManager.InputState(InputManager.InputState.InputStateBehavior.CATCH_ONLY_ONCE);

        inputManager.setMouseButtonMiddleStateObject(middleMouseButton);
        inputManager.setKeyboardStateObject(KeyEvent.VK_LEFT, left);
        inputManager.setKeyboardStateObject(KeyEvent.VK_RIGHT, right);
        inputManager.setKeyboardStateObject(KeyEvent.VK_UP, up);
        inputManager.setKeyboardStateObject(KeyEvent.VK_DOWN, down);
        inputManager.setMouseWheelUpStateObject(mouseWheelUp);
        inputManager.setMouseWheelDownStateObject(mouseWheelDown);

        cameraPosition = new Vector3D(0, 15, 50);
        cameraOrientation = new Vector3D();
        setCameraOrientation(30, 90);
        recalcCameraSpot();
    }

    
    public void updateCamera(long deltaTime) {
        if (mouseWheelDown.isPressed()) {
            zoomDirection = ZoomDirection.UP;
            zoomYTo = cameraPosition.y + ZOOM_STEP_Y;
            if (cameraPosition.y < CAMERA_MIN_Y) {
                zoomYTo = CAMERA_MIN_Y + ZOOM_STEP_Y;
            }
            zooming = true;
        }
        if (mouseWheelUp.isPressed()) {
            if (cameraPosition.y > CAMERA_MIN_Y) {
                zoomDirection = ZoomDirection.DOWN;
                zoomYTo = cameraPosition.y - ZOOM_STEP_Y;
                if (zoomYTo < CAMERA_MIN_Y) {
                    zoomYTo = CAMERA_MIN_Y;
                }
                zooming = true;
            }
        }

        // 1) Zoom
        if (zooming) {
            if (zoomDirection == ZoomDirection.UP) {
                cameraPosition.subtract(Vector3D.multiply(ZOOM_SPEED_Y*deltaTime, cameraOrientation));
                if (cameraPosition.y >= zoomYTo) {
                    zooming = false;
                }
            }
            else if (zoomDirection == ZoomDirection.DOWN) {
                cameraPosition.add(Vector3D.multiply(ZOOM_SPEED_Y*deltaTime, cameraOrientation));
                if (cameraPosition.y <= zoomYTo) {
                    zooming = false;
                }
            }
        }
    }

    private void recalcCameraSpot() {
        // vypočítat průsečík s rovinou y = 0
        // Cy + k*vy = 0
        cameraSpot.y = 0;
        double k = - cameraPosition.y / cameraOrientation.y;
        cameraSpot.x = cameraPosition.x + k*cameraOrientation.x;
        cameraSpot.z = cameraPosition.z + k*cameraOrientation.z;
    }

    private void setCameraOrientation(float cameraXRotation, float cameraYRotation) {
        cameraOrientation.x = Math.cos(cameraYRotation/180*Math.PI);
        cameraOrientation.z = -Math.sin(cameraYRotation/180*Math.PI);
        cameraOrientation.y = -Math.tan(cameraXRotation/180*Math.PI);

        cameraOrientation.unit();
        System.out.println(cameraOrientation);
    }

    public Vector3D getCameraPosition() {
        return cameraPosition;
    }

    public float getCameraXRotation() {
        //System.out.println(Math.atan(-cameraOrientation.y)*180/Math.PI);
        double cameraXZsize = Math.sqrt(cameraOrientation.x*cameraOrientation.x+cameraOrientation.z*cameraOrientation.z);
        return (float)(Math.atan(-cameraOrientation.y/cameraXZsize)*180/Math.PI);
        
    }

    public float getCameraYRotation() {
        return (float)(Math.atan2(-cameraOrientation.z, cameraOrientation.x)*180/Math.PI);
    }

}
